<!--
 * @Description: 金额组件
 * 示例：<tw-money v-model="amount"></tw-money>
 * @Author: DHL
 * @Date: 2022-10-10 13:23:43
 * @LastEditors: DHL
 * @LastEditTime: 2022-11-16 14:07:31
-->
<template>
  <el-input
    v-model="moneyValueFormat"
    @blur="handleBlur"
    @change="handleChange"
    @focus="handleFocus"
    @input="handleInput"
    @clear="handleClear"
    :placeholder="placeholder"
  />
</template>

<script setup lang="ts">
  import BigNum from '/@/utils/bigNum'

  interface Props {
    modelValue: number

    /**
     * 精度
     */
    precision?: number

    /**
     * 单位
     */
    unit?: string

    /**
     * 最大长度
     */
    maxLength?: number

    /**
     * 提示信息
     */
    placeholder?: string
  }

  const props = withDefaults(defineProps<Props>(), {
    modelValue: 0,
    precision: 2,
    unit: '',
    maxLength: 10,
    placeholder: '请输入金额'
  })

  const emits = defineEmits(['update:modelValue', 'change'])

  /**
   * 金额实际值
   */
  let moneyValue = 0

  /**
   * 金额显示值
   */
  const moneyValueFormat = ref('')

  watch(
    () => props.modelValue,
    (newValue) => {
      moneyValue = newValue || 0
      moneyValueFormat.value = moenyFormat(moneyValue, props.precision)
    },
    {
      immediate: true
    }
  )

  //////////////////////////////////////////////////
  // 函数
  //////////////////////////////////////////////////

  /**
   * 金额格式化
   * @param moeny   金额String||Number
   * @param precision   小数位数Number(0-20)
   * @param unit    是否带单位Boolean
   */
  function moenyFormat(moeny, precision = 2, unit = false) {
    if (moeny == '') moeny = '0'
    precision = precision > 0 && precision <= 20 ? precision : 2
    moeny = parseFloat((moeny + '').replace(/[^\d\.-]/g, '')).toFixed(precision) + ''
    let l = moeny.split('.')[0].split('').reverse()
    let r = moeny.split('.')[1]
    let t = ''
    for (let i = 0; i < l.length; i++) {
      t += l[i] + ((i + 1) % 3 == 0 && i + 1 != l.length ? ',' : '')
    }
    if (unit) {
      return t.split('').reverse().join('') + '.' + r + '元'
    } else {
      return t.split('').reverse().join('') + '.' + r
    }
  }

  /**
   * 输入事件
   */
  function handleInput() {
    let newStr = moneyValueFormat.value

    // pc端中文输入法'。' ==> '.'
    newStr = (newStr + '').replace('。', '.').replace(/[^0-9.]/g, '')

    // .xxx ==> 0.xxx
    if (newStr.startsWith('.')) {
      newStr = '0.' + newStr.slice(1)
    }

    // 0xxx ==> xxx
    if (newStr.startsWith('0') && newStr.length > 1 && !newStr.slice(1).startsWith('.')) {
      newStr = newStr.slice(1)
    }

    moneyValueFormat.value = newStr
    moneyValue = new BigNum(newStr).toFixed(props.precision).parse()
  }

  /**
   * 获取焦点
   */
  function handleFocus() {
    moneyValueFormat.value = moneyValue + ''
  }

  /**
   * 失去焦点
   */
  function handleBlur() {
    emits('update:modelValue', new BigNum(moneyValue).toFixed(props.precision).parse())
    moneyValueFormat.value = moenyFormat(moneyValue, props.precision)
  }

  /**
   * 值改变事件
   */
  function handleChange() {
    const value = new BigNum(moneyValue).toFixed(props.precision).parse()
    moneyValueFormat.value = moenyFormat(moneyValue, props.precision)
    emits('update:modelValue', value)
    emits('change', value)
  }

  /**
   * 清空
   */
  function handleClear() {
    emits('update:modelValue', 0)
    moneyValue = 0
    moneyValueFormat.value = moenyFormat(moneyValue, props.precision)
    emits('change', 0)
  }

  //////////////////////////////////////////////////
  // 生命周期
  //////////////////////////////////////////////////
  onMounted(() => {})
</script>

<style scoped lang="scss"></style>
